RECURSION

ecursion is a powerful idea that makes it possible to solve some problems easily that would otherwise be quite difficult. Recursion cannot be used in all programming languages, but it is supported by most modern languages, including MATLAB.
A definition of a concept that uses the concept itself is called a recursive definition, and the use of a concept in the definition of the concept is called recursion.
% function f=rfact(n)
% if n==0
% f=1
% else
% f=n*rfact(n-1)
% end
% end
rfact(3)
ans = 6

Computer Memory

Local variable stored in Stack. we can iamgige like piles nof dishes (e.g. in rfact function n,f)
once it completed step by step it start coming back. in this process variables are storing in stack.
rfact(0)
ans = 1
rfact(1)
ans = 1
rfact(5)
ans = 120
% rfact(2.5)
%out of memory. infinite recursion
so now we have check condition for non negative scaler integer.
help fix
fix Round towards zero.
fix(X) rounds the elements of X to the nearest integers
towards zero.

See also floor, round, ceil.

Reference page for fix
Other functions named fix
help isscalar
isscalar True if input is a scalar.
isscalar(S) returns logical 1 (true) if SIZE(S) returns [1 1] and
logical 0 (false) otherwise.

See also isvector, isrow, iscolumn, ismatrix, isnumeric, islogical, ischar,
isempty, size.

Reference page for isscalar
Other functions named isscalar
% function f=rfact(n)
% if ~isscalar(n) || n~=fix(n) || n<0
% error("non negative scaler integer input expected")
% end
% if n==0
% f=1;
% else
% f=n*rfact(n-1);
% end
% end
rfact(2.5)
Error using rfact (line 3)
non negative scaler integer input expected
rfact(5)
ans = 120
rfact(600)
ans = Inf
rfact(50000)
ans = Inf
% rfact(69899)
rfact(69899)
Out of memory. The likely cause is an infinite recursion within the program.
Error in rfact (line 8)
f=n*rfact(n-1);
it means there not enought memory in stack to carry out.

Conditional check

we can an conditional check, right click on 2- and add condtional check.
rfact(4)
2 if ~isscalar(n) ||n~=fix(n) || n<0
we can see stack, and run code linr by line and can variable change in workspace.
End debugging session by clicking Quit Dbugging

non iterative factorial funtion

% function f=ifact(n)
% if ~isscalar(n) || n~=fix(n) || n<0
% error("non negative scaler integer input expected")
% end
% f=1;
% for ii=1:n
% f=ii*f;
% end
% end
ifact(3)
ans = 6
ifact(0)
ans = 1
ifact(69899)
ans = Inf
%rfact(69899)
rfact(69899)
Out of memory. The likely cause is an infinite recursion within the program.
Error in rfact (line 8)
f=n*rfact(n-1);
ifact(69899)
ans =
Inf
So, here we can see iterative algorithm is better.

Recursive versus Iterative

Sierpiński triangle

help clf
clf Clear current figure.
clf deletes all children of the current figure with visible handles.

clf RESET deletes all children (including ones with hidden
handles) and also resets all figure properties, except Position,
Units, PaperPosition and PaperUnits, to their default values.

clf(FIG) or clf(FIG,'RESET') clears the single figure with handle FIG.

FIG_H = clf(...) returns the handle of the figure.

See also cla, reset, hold.

Reference page for clf
help axis
axis Control axis scaling and appearance.
axis([XMIN XMAX YMIN YMAX]) sets scaling for the x- and y-axes
on the current plot.
axis([XMIN XMAX YMIN YMAX ZMIN ZMAX]) sets the scaling for the
x-, y- and z-axes on the current 3-D plot.
axis([XMIN XMAX YMIN YMAX ZMIN ZMAX CMIN CMAX]) sets the
scaling for the x-, y-, z-axes and color scaling limits on
the current axis (see CAXIS).
V = axis returns a row vector containing the scaling for the
current plot. If the current view is 2-D, V has four
components; if it is 3-D, V has six components.

axis AUTO returns the axis scaling to its default, automatic
mode where, for each dimension, 'nice' limits are chosen based
on the extents of all line, surface, patch, and image children.
axis MANUAL freezes the scaling at the current limits, so that if
HOLD is turned on, subsequent plots will use the same limits.
axis TIGHT sets the axis limits to the range of the data.
axis FILL sets the axis limits and PlotBoxAspectRatio so that
the axis fills the position rectangle. This option only has
an effect if PlotBoxAspectRatioMode or DataAspectRatioMode are
manual.

axis IJ puts MATLAB into its "matrix" axes mode. The coordinate
system origin is at the upper left corner. The i axis is
vertical and is numbered from top to bottom. The j axis is
horizontal and is numbered from left to right.
axis XY puts MATLAB into its default "Cartesian" axes mode. The
coordinate system origin is at the lower left corner. The x
axis is horizontal and is numbered from left to right. The y
axis is vertical and is numbered from bottom to top.

axis EQUAL sets the aspect ratio so that equal tick mark
increments on the x-,y- and z-axis are equal in size. This
makes SPHERE(25) look like a sphere, instead of an ellipsoid.
axis IMAGE is the same as axis EQUAL except that the plot
box fits tightly around the data.
axis SQUARE makes the current axis box square in size.
axis NORMAL restores the current axis box to full size and
removes any restrictions on the scaling of the units.
This undoes the effects of axis SQUARE and axis EQUAL.
axis VIS3D freezes aspect ratio properties to enable rotation of
3-D objects and overrides stretch-to-fill.

axis OFF turns off all axis labeling, tick marks and background.
axis ON turns axis labeling, tick marks and background back on.

axis(H,...) changes the axes handles listed in vector H.

See also axes, grid, subplot, xlim, ylim, zlim, rlim

Reference page for axis
Other functions named axis
s = 1; c = [0;0]; % s = length of side, c = center
clf
axis([c(1)-s/2,c(1)+s/2,c(2)-s/2,c(2)+s/2],'equal')
plot(c(1)-[s,0,-s,s]/2,c(2)-[s,-s,s,s]*sqrt(3)/4,'k')
plot([1,5,2,3,5,0.5])
plot([1,2,3,1],[3/4,3,3/4,3/4])
plot(c(1)-[s,0,-s,s]/2,c(2)-[s,-s,s,s]*sqrt(3)/4)
plot([s,0,-s,s]/2,[s,-s,s,s]*sqrt(3)/4)
plot(-[s,0,-s,s]/2,-[s,-s,s,s]*sqrt(3)/4)
plot([-0.5,0,0.5,-0.5],[-0.5,0.5,-0.5,-0.5])
3.^[1:3]
ans = 1×3
3 9 27
% function sierpinski(depth)
% s = 1; c = [0;0]; % s = length of side, c = center
% clf; axis([c(1)-s/2,c(1)+s/2,c(2)-s/2,c(2)+s/2],'equal');
% title(sprintf('Sierpinski Triangle with Depth = %d', depth))
% hold on;
% sier(depth, s, c);
% hold off;
% end
% function sier(d, s, c)
% if d <= 0 % base case
% plot(c(1)-[s,0,-s,s]/2,c(2)-[s,-s,s,s]*sqrt(3)/4,'k');
% else % recursive case
% s = s/2; % cuts size in half
% h = s*sqrt(3)/2; % height
% sier( d-1, s, c - [s;h]/2 ); % bottom left
% sier( d-1, s, c + [0;h]/2 ); % top middle
% sier( d-1, s, c + [s;-h]/2 ); % bottom right
% end
% end
sierpinski(8)
No of time sieri function is called
so in depth 8 calculation-- 9841 time
sum(3.^(0:8))
ans = 9841
No. of smallest triengl=3^depth=3^8=6561
3^8
ans = 6561
Max height stack reaches here is=(depth)+1=9
sierpinski(1);
for d=[1:7];
t0=cputime;
sierpinski(d);
t(d)=cputime-t0
end
t = 1×7
0.2500 0.0469 0.1094 0.1719 0.3750 0.9844 3.1094
t = 1×7
0.2500 0.0469 0.1094 0.1719 0.3750 0.9844 3.1094
t = 1×7
0.2500 0.0469 0.1250 0.1719 0.3750 0.9844 3.1094
t = 1×7
0.2500 0.0469 0.1250 0.2188 0.3750 0.9844 3.1094
t = 1×7
0.2500 0.0469 0.1250 0.2188 0.3906 0.9844 3.1094
t = 1×7
0.2500 0.0469 0.1250 0.2188 0.3906 1.0000 3.1094
t = 1×7
0.2500 0.0469 0.1250 0.2188 0.3906 1.0000 2.9219
plot(t);
grid on

Now we will plot this in efficient way

% function sierpinskiE(depth)
% s = 1; c = [0;0]; % s = length of side, c = center
% clf; axis([c(1)-s/2,c(1)+s/2,c(2)-s/2,c(2)+s/2],'equal');
% title(sprintf('Sierpinski Triangle with Depth = %d', depth))
% hold on;
% plot(1/2*[-1,0,1,-1],sqrt(3)/4*[-1,1,-1,-1],'r--');
% pts = sier(depth, s, c, []);
% plot(pts(1,:),pts(2,:),'k-');
% hold off;
% end
% function pts = sier(d, s, c, pts)
% if d <= 0 % base case
% pts = [pts, c + [[-s,0,s,-s,nan]/2;sqrt(3)*[-s,s,-s,-s,nan]/4]];
% else % recursive case
% s = s/2; % cuts size in half
% h = s*sqrt(3)/2; % height
% pts = sier( d-1, s, c - [s;h]/2, pts ); % bottom left
% pts = sier( d-1, s, c + [0;h]/2, pts ); % top middle
% pts = sier( d-1, s, c + [s;-h]/2, pts ); % bottom right
% end
% end
sierpinskiE(7)
in 1st funcrtion sierpinski it is not possible to plot to depth 12 as computes hanged.
but sierpinskiE we can easily plot to depth 12 in less time.
sierpinskiE(1);
for d=[1:12];
t0=cputime;
sierpinskiE(d);
t(d)=cputime-t0
end
t = 1×7
0.3125 0.0781 0.0469 0.0469 0.0625 0.0938 0.0625
t = 1×7
0.3125 0.0469 0.0469 0.0469 0.0625 0.0938 0.0625
t = 1×7
0.3125 0.0469 0.0938 0.0469 0.0625 0.0938 0.0625
t = 1×7
0.3125 0.0469 0.0938 0.0469 0.0625 0.0938 0.0625
t = 1×7
0.3125 0.0469 0.0938 0.0469 0.0313 0.0938 0.0625
t = 1×7
0.3125 0.0469 0.0938 0.0469 0.0313 0.1094 0.0625
t = 1×7
0.3125 0.0469 0.0938 0.0469 0.0313 0.1094 0.0938
t = 1×8
0.3125 0.0469 0.0938 0.0469 0.0313 0.1094 0.0938 0.1406
t = 1×9
0.3125 0.0469 0.0938 0.0469 0.0313 0.1094 0.0938 0.1406 0.1563
t = 1×10
0.3125 0.0469 0.0938 0.0469 0.0313 0.1094 0.0938 0.1406 0.1563 0.3906
t = 1×11
0.3125 0.0469 0.0938 0.0469 0.0313 0.1094 0.0938 0.1406 0.1563 0.3906 0.8906
t = 1×12
0.3125 0.0469 0.0938 0.0469 0.0313 0.1094 0.0938 0.1406 0.1563 0.3906 0.8906 2.7344
plot(t);
grid on

Greatest Commen Deviser (GCD)

We studies two recursive example
Now lts understand this,
% function d= rgcd(x, y)
% if (~isscalar(x) || x~=fix(x) || x<0 || ...
% ~isscalar(y) || y~=fix(y) || y<0)
% error("X, Y must be non negative scalar");
% end
% a=max([x,y]);
% b=min([x,y]);
% if b==0;
% d=a;
% else
% d=rgcd(b,rem(a,b));
% end
% end
rgcd(21,14)
ans = 7
Iterative version of GCD
% function d= igcd(x, y)
% if (~isscalar(x) || x~=fix(x) || x<0 || ...
% ~isscalar(y) || y~=fix(y) || y<0)
% error("X, Y must be non negative scalar");
% end
% a=max([x,y]);
% b=min([x,y]);
% while b~=0;
% r=rem(a,b);
% a=b;
% b=r;
% end
% d=a;
% end
igcd(102,54)
ans = 6

Assignment

Problem 1: Digit Summation

Write a recursive function to sum the individual digits of an input number.
my solution
% digit summation code
% function s=digit_sum(n)
% if (~isscalar(n) || n~=fix(n) || n<0)
% error("n must be non negative scalar");
% end
%
% if n==0;
% s=0;
% else
% s=digit_sum(fix(n*0.1))+n-(fix(n*0.1))*10;
% end
%
% end
digit_sum(12345)
ans = 15
Coursera solution
% function res = cdigit_sum(n)
% if n < 10
% res = n;
% else
% res = cdigit_sum(floor(n/10)) + rem(n,10);
% end
% end
cdigit_sum(12345)
ans = 15

Problem 2: Maximum Element

Write a recursive function to find the maximum element in a vector.
my solution
v=[1,32,2,58,-55,0,12];
n=length(v)
n = 3
v(1)
ans = 1
v(2:n)
ans = 1×2
32 2
length(v(2:n))
ans = 2
numel(v)
ans = 3
Using max function
% function m=max_in(v)
%
% n=length(v);
%
% if n==1;
% m=v(1);
% else
% m = max(v(1),max_in(v(2:n)));
% end
%
%
% end
max_in(v)
ans = 58
without using max function
% function m=cmax_in(v)
%
% n=length(v);
%
% if n==1;
% m=v(1);
% else
% m = cmax_in(v(2:n));
% if v(1)>m
% m = v(1);
% end
%
% end
cmax_in(v)
ans = 58
Solution by coursera
% function mx = recursive_max(v)
% if length(v) == 1
% mx = v(1);
% else
% % Each recursion, v(2:end) becomes smaller by 1-element
% mx = bigger(v(1),recursive_max(v(2:end)));
% end
% end
% % Cannot use the max function. Use helper function to return the larger of
% % two element
% function c = bigger(a,b)
% c = a;
% if a < b
% c = b;
% end
% end
recursive_max(v)
ans = 58

Variable Number of Arguments

help nargin
nargin Number of function input arguments.
Inside the body of a user-defined function, nargin returns
the number of input arguments that were used to call the
function.

nargin(FUN) returns the number of declared inputs for the
function FUN. The number of arguments is negative if the
function has a variable number of input arguments. FUN can be
a function handle that maps to a specific function, or a character
vector or string scalar that contains the name of that function.

See also nargout, varargin, narginchk, inputname, mfilename.

Reference page for nargin
Other functions named nargin
help nargout
nargout Number of function output arguments.
Inside the body of a user-defined function, nargout returns the
number of output arguments that were used to call the function.

nargout(FUN) returns the number of declared outputs for the
function FUN. The number of arguments is negative if the
function has a variable number of output arguments. FUN can be
a function handle that maps to a specific function, or a character
vector or string scalar that contains the name of that function.

See also nargin, varargout, nargoutchk, inputname, mfilename.

Reference page for nargout
Other functions named nargout
help varargin
varargin Variable length input argument list.
Allows any number of arguments to a function. The variable
varargin is a cell array containing the optional arguments to the
function. varargin must be declared as the last input argument
and collects all the inputs from that point onwards. In the
declaration, varargin must be lowercase (i.e., varargin).

For example, the function,

function myplot(x,varargin)
plot(x,varargin{:})

collects all the inputs starting with the second input into the
variable "varargin". MYPLOT uses the comma-separated list syntax
varargin{:} to pass the optional parameters to plot. The call,

myplot(sin(0:.1:1),'color',[.5 .7 .3],'linestyle',':')

results in varargin being a 1-by-4 cell array containing the
values 'color', [.5 .7 .3], 'linestyle', and ':'.

See also varargout, nargin, nargout, inputname, function, lists, paren.

Reference page for varargin
help varagout
--- help for varargout ---

varargout Variable length output argument list.
Allows any number of output arguments from a function. The
variable varargout is a cell array containing the
optional output arguments from the function. varargout must be
declared as the last output argument and must contain all the
outputs after that point onwards. In the declaration, varargout
must be lowercase (i.e., varargout).

varargout is not initialized when the function is invoked. You
must create it before your function returns. Use NARGOUT to
determine the number of outputs to produce.

For example, the function,

function [s,varargout] = mysize(x)
nout = max(nargout,1)-1;
s = size(x);
for i=1:nout, varargout(i) = {s(i)}; end

returns the size vector and optionally individual sizes. So,

[s,rows,cols] = mysize(rand(4,5));

returns s = [4 5], rows = 4, cols = 5.

See also varargin, nargin, nargout, function, lists, paren.

Reference page for varargout
help find
find Find indices of nonzero elements.
I = find(X) returns the linear indices corresponding to
the nonzero entries of the array X. X may be a logical expression.
Use IND2SUB(SIZE(X),I) to calculate multiple subscripts from
the linear indices I.

I = find(X,K) returns at most the first K indices corresponding to
the nonzero entries of the array X. K must be a positive integer,
but can be of any numeric type.

I = find(X,K,'first') is the same as I = find(X,K).

I = find(X,K,'last') returns at most the last K indices corresponding
to the nonzero entries of the array X.

[I,J] = find(X,...) returns the row and column indices instead of
linear indices into X. This syntax is especially useful when working
with sparse matrices. If X is an N-dimensional array where N > 2, then
J is a linear index over the N-1 trailing dimensions of X.

[I,J,V] = find(X,...) also returns a vector V containing the values
that correspond to the row and column indices I and J.

Example:
A = magic(3)
find(A > 5)

finds the linear indices of the 4 entries of the matrix A that are
greater than 5.

[rows,cols,vals] = find(speye(5))

finds the row and column indices and nonzero values of the 5-by-5
sparse identity matrix.

See also sparse, ind2sub, relop, nonzeros.

Reference page for find
Other functions named find
v=[1,0,32,2,58,-55,0,2];
find(v==2)
ans = 1×2
4 8
find(v==58)
ans = 5
find(v==0)
ans = 1×2
2 7
find(v==9) % not in list
ans =

1×0 empty double row vector
find(v) %in ans 2, 6 is missing as it is zero
ans = 1×6
1 3 4 5 6 8
find(v,3) %in ans 2 is missing as it is zero
ans = 1×3
1 3 4
help rng
rng Control the random number generator used by RAND, RANDI, and RANDN.
rng(SD) seeds the random number generator using the non-negative
integer SD so that RAND, RANDI, and RANDN produce a predictable
sequence of numbers.

rng('shuffle') seeds the random number generator based on the current
time so that RAND, RANDI, and RANDN produce a different sequence of
numbers after each time you call rng.

rng(SD,GENERATOR) and rng('shuffle',GENERATOR) additionally specify the
type of the random number generator used by RAND, RANDI, and RANDN.
GENERATOR is one of:

Generator Description
------------------------------------------------------------------
'twister' Mersenne Twister
'simdTwister' SIMD-oriented Fast Mersenne Twister
'combRecursive' Combined Multiple Recursive
'multFibonacci' Multiplicative Lagged Fibonacci
'v5uniform' Legacy MATLAB 5.0 uniform generator
'v5normal' Legacy MATLAB 5.0 normal generator
'v4' Legacy MATLAB 4.0 generator

rng('default') puts the settings of the random number generator used by
RAND, RANDI, and RANDN to their default values so that they produce the
same random numbers as if you restarted MATLAB. In this release, the
default settings are the Mersenne Twister with seed 0.

SCURR = rng returns the current settings of the random number generator
used by RAND, RANDI, and RANDN. The settings are returned in a
structure SCURR with fields 'Type', 'Seed', and 'State'.

rng(S) restores the settings of the random number generator used by
RAND, RANDI, and RANDN back to the values captured previously by
S = rng.

SPREV = rng(...) returns the previous settings of the random number
generator used by RAND, RANDI, and RANDN before changing the settings.

Example 1: Retrieve and Restore Generator Settings
s = rng % get the current generator settings
x = rand(1,5) % RAND generates some values
rng(s) % restore the generator settings
y = rand(1,5) % generate the same values so x and y are equal

Example 2: Restore Settings for Legacy Generator
prevS = rng(0,'v5uniform') % use legacy generator, save previous settings
x = rand % legacy startup value .9501
rng(prevS) % restore the previous settings

See Replace Discouraged Syntaxes of rand and randn to use rng to replace
RAND or RANDN with the 'seed', 'state', or 'twister' inputs.

See also rand, randi, randn, RandStream, now.

Reference page for rng
fprintf can handle unlimited no of argument, we can also erite function which can handle unlimited no of argument.
Function that cant handle unlimited no of argument
% function index = find_first(v,e)
% if nargin == 0
% error('At least one argument is required')
% elseif nargin == 1
% e = 0;
% end
% index = 0;
% indices = find(v == e);
% if ~isempty(indices)
% index = indices(1);
% end
% end
rng(0);
v=randi([-3,3],1,12)
v = 1×12
2 3 -3 3 1 -3 -2 0 3 3 -2 3
find_first(v,1) %one is at index 5
ans = 5
find_first(v,2)
ans = 1
find_first(v,12) %not in v so 0
ans = 0
find_first(v,0)
ans = 8
find_first(v) %2nd argumnet not given so by default take 0
ans = 8
Enters multiple argument in fprintf via varargin-
varargin can take maltiple argument
% function print_all(varargin)
% for ii = 1:nargin
% fprintf('Here is input argument number %d: %d\n', ii, varargin{ii})
% end
% end
print_all(pi)
Here is input argument number 1: 3.141593e+00
print_all(7,-3)
Here is input argument number 1: 7
Here is input argument number 2: -3
print_all(4,5,6,8,-3,8)
Here is input argument number 1: 4
Here is input argument number 2: 5
Here is input argument number 3: 6
Here is input argument number 4: 8
Here is input argument number 5: -3
Here is input argument number 6: 8
help fprintf
fprintf Write formatted data to text file.
fprintf(FID, FORMAT, A, ...) applies the FORMAT to all elements of array A and
any additional array arguments in column order, and writes the data to a text
file. FID is an integer file identifier. Obtain FID from FOPEN, or set it to 1
(for standard output, the screen) or 2 (standard error). fprintf uses the
encoding scheme specified in the call to FOPEN.

fprintf(FORMAT, A, ...) formats data and displays the results on the screen.

COUNT = fprintf(...) returns the number of bytes that fprintf writes.

FORMAT is a character vector that describes the format of the output fields, and
can include combinations of the following:

* Conversion specifications, which include a % character, a
conversion character (such as d, i, o, u, x, f, e, g, c, or s), and optional
flags, width, and precision fields. For more details, type "doc fprintf" at
the command prompt.

* Literal text to print.

* Escape characters, including:
\b Backspace '' Single quotation mark
\f Form feed %% Percent character
\n New line \\ Backslash
\r Carriage return \xN Hexadecimal number N
\t Horizontal tab \N Octal number N
For most cases, \n is sufficient for a single line break. However, if you
are creating a file for use with Microsoft Notepad, specify a combination of
\r\n to move to a new line.

Notes:

If you apply an integer or text conversion to a numeric value that contains a
fraction, MATLAB overrides the specified conversion, and uses %e.

Numeric conversions print only the real component of complex numbers.

Example: Create a text file called exp.txt containing a short table of the
exponential function.

x = 0:.1:1;
y = [x; exp(x)];
fid = fopen('exp.txt','w');
fprintf(fid,'%6.2f %12.8f\n',y);
fclose(fid);

Examine the contents of exp.txt:

type exp.txt

MATLAB returns:
0.00 1.00000000
0.10 1.10517092
...
1.00 2.71828183

See also fopen, fclose, fscanf, fread, fwrite, sprintf, disp.

Reference page for fprintf
Other functions named fprintf
help sprintf
sprintf Write formatted data to string or character vector
STR = sprintf(FORMAT, A, ...) applies FORMAT to all elements of
array A and any additional array arguments in column order, and returns
the results as STR. FORMAT can be a character vector or a string
scalar. The data type of STR is the same as the data type of FORMAT.

[STR, ERRMSG] = sprintf(FORMAT, A, ...) returns an error message when
the operation is unsuccessful. Otherwise, ERRMSG is empty.

sprintf is the same as FPRINTF except that it returns the data in a
MATLAB variable rather than writing to a file.

FORMAT describes the format of the output fields, and can include
combinations of the following:

* Conversion specifications, which include a % character, a
conversion character (such as d, i, o, u, x, f, e, g, c, or s),
and optional flags, width, and precision fields. For more
details, type "doc sprintf" at the command prompt.

* Literal text to print.

* Escape characters, including:
\b Backspace '' Single quotation mark
\f Form feed %% Percent character
\n New line \\ Backslash
\r Carriage return \xN Hexadecimal number N
\t Horizontal tab \N Octal number N%
where \n is a line termination character on all platforms.

Notes:

If you apply an integer or text conversion to a numeric value that
contains a decimal, MATLAB overrides the specified conversion, and
uses %e to express the value in exponential notation.

Numeric conversions print only the real component of complex numbers.

Examples
sprintf('%0.5g',(1+sqrt(5))/2) % 1.618
sprintf('%0.5g',1/eps) % 4.5036e+15
sprintf('%15.5f',1/eps) % 4503599627370496.00000
sprintf('%d',round(pi)) % 3
sprintf('%s','hello') % hello
sprintf('The array is %dx%d.',2,3) % The array is 2x3.

See also fprintf, sscanf, num2str, int2str, char, string, compose.

Reference page for sprintf
Other functions named sprintf
sprintf('the first three positive integer are %d,%d and %d',1,2,3)
ans = 'the first three positive integer are 1,2 and 3'
We are goint to write a function as,
% function out = print_num(format,varargin)
% out = '';
% argindex = 1;
% skip = false;
% for ii = 1:length(format)
% if skip
% skip = false;
% else
% if format(ii) ~= '%'
% out(end+1) = format(ii);
% else
% if ii+1 > length(format)
% break;
% end
% if format(ii+1) == '%'
% out(end+1) = '%';
% else
% if argindex >= nargin
% error('not enough input arguments');
% end
% out = [out num2str(varargin{argindex},format(ii:ii+1))];
% argindex = argindex + 1;
% end
% skip = true;
% end
% end
% end
% end
print_num('the first three positive integer are %d,%d and %d',1,2,3)
ans = 'the first three positive integer are 1,2 and 3'
pct=20;
a=934.40;
print_num('%d%% of %f is %f',pct, a, a*pct/100)
ans = '20% of 934.400000 is 186.880000'
% function varargout = distribute(v)
% for ii = 1:length(v)
% varargout{ii} = v(ii);
% end
% end
[a,b,c]=distribute([14,-pi,0])
a = 14
b = -3.1416
c = 0
[a,b]=distribute([14,-pi,0])
a = 14
b = -3.1416
%[a,b,c]=distribute([14,-pi,0,g]) error will come
One last detail that we should mention is that, just as with varargin, you can include normal local variables along with varargout in the list of formal output arguments in the function signature. But as with varargin, varargout must be the last argument in the list. In analogy to varargin, varargout holds any excess output arguments that come after the normal ones.
All right, we've relearned what nargin and nargout do, and we've learned what varargin and varargout do. The first two count arguments, and the second two store variable numbers of arguments. That's how MATLAB allows you to define functions that can handle unlimited numbers of arguments.

Assignment

Problem 1: Name-value Pairs

Write a function that pairs up the keys and the respective values from unspecified number of input
% % Problem 1: Name-value Pairs
% % Write a function that pairs up the keys and the
% % respective values from unspecified number of input
%
% function db = name_value_pairs(varargin)
%
% if nargin>0 && rem(nargin, 2) == 0
% db = cell(nargin/2, 2);
%
%
% for ii = 1:nargin
% if rem(ii,2) ~= 0
% if ischar(varargin{ii})
% db{(ii+1)/2,1} = varargin{ii};
% else
% db ={};
% return;
% end
% else
% db{ii/2,2} = varargin{ii};
% end
%
%
% end
% else
% db = {};
% end
% end
name_value_pairs('name','John Smith','age',32,'children',{'Joe','Jill'})
ans = 3×2 cell array
{'name' } {'John Smith'}
{'age' } {[ 32]}
{'children'} {1×2 cell }
database = struct with fields:
Name: "Adam"
ID: 11111
database = 1×2 struct array with fields:
Name
ID
ans = struct with fields:
Name: "Adam"
ID: 11111
ans = struct with fields:
Name: "Eve"
ID: 22222

Problem 2: Data Entry

Write a function that keys in new voters' information into the current database.
% function database = voters(database,varargin)
% % Get the length of the input database
% count = length(database);
%
% % Create a copy of the database. This will be the new database if input
% % is valid
% tmp = database;
%
% % Names and IDs come in pairs. Increment loop counter by 2
% for ii = 1:2:length(varargin)
% % Make sure the Name is a char or string
% if ischar(varargin{ii}) || isstring(varargin{ii})
% count = count + 1;
% tmp(count).Name = string(varargin{ii});
% % Make sure there is a valid ID
% if ii+1 <= length(varargin) && isnumeric(varargin{ii+1}) && round(varargin{ii+1}) == varargin{ii+1}
% tmp(count).ID = varargin{ii+1};
% else
% % Not valid input. Return original database
% return;
% end
% else
% % Not valid input. Return orginal database
% return;
% end
% end
% % All inputs valid. Update database.
% database = tmp;
% end
database = voters([], 'Adam', 11111)
database = struct with fields:
Name: "Adam"
ID: 11111
database = voters(database, 'Eve', 22222)
database = 1×2 struct array with fields:
Name
ID
database(1)
ans = struct with fields:
Name: "Adam"
ID: 11111
database(2)
ans = struct with fields:
Name: "Eve"
ID: 22222

Function Handles and Nested Functions

For example, some functions can take other functions as arguments. The integral function, for instance, uses numerical approximation to estimate the integral of any function supplied as an input argument. Another case will come up in a couple of weeks when we'll show you how to create a graphical user interface, and you'll learn that you can specify which function should be called when various buttons are clicked. These are termed callback functions and you specify them using function handles
trig=@sin
trig = function_handle with value:
@sin
x=trig(pi/2)
x = 1
plot(trig(0:0.01:2*pi))
close all
x=trig
x = function_handle with value:
@sin
This time, MATLAB saw that we did not include an input argument, so instead of using the function handle to call the sin function and copying the return value into X, you just copy the function handle itself into X. So now we can call a sin function with X.
x(pi/2)
ans = 1
But what about functions that you call with no arguments? Like the function Pi which may not seem like a function but actually is a function, a built-in function. It just doesn't look like a function because it takes no input arguments and returns just one output argument. Let's assign a function handle for Pi to the variable mypi.
x=pi
x = 3.1416
mypi=@pi
mypi = function_handle with value:
@pi
Now let's try to use it to give X the value Pi again. Well, that didn't work.
x=mypi
x = function_handle with value:
@pi
To call the function, just include empty parentheses like this,
y=mypi()
y = 3.1416
If you want to put together an array of several function handles, you can use regular arrays
xpt={@sin @cos @plot}
xpt = 1×3 cell array
{@sin} {@cos} {@plot}
xpt{2}(0)
ans = 1
Calling the function through cell array indexing might look a little bit strange at first. This command calls the cosine function with an input argument of zero.
xpt{1}(pi/2)
ans = 1
It first uses curly braces to select the appropriate element of the cell array and then uses regular parentheses to provide the input arguments to the selected function.
Here's a command "impress your friends."
xpt{3}(xpt{1}(-pi:0.01:pi))
We just called plot by putting a three in curly braces to draw the sign by putting a one in curly braces from minus pi to pi.
help fplot
fplot Plot 2-D function
fplot(FUN) plots the function FUN between the limits of the current
axes, with a default of [-5 5].

fplot(FUN,LIMS) plots the function FUN between the x-axis limits
specified by LIMS = [XMIN XMAX].

fplot(...,'LineSpec') plots with the given line specification.

fplot(X,Y,LIMS) plots the parameterized curve with coordinates
X(T), Y(T) for T between the values specified by LIMS = [TMIN TMAX].

H = fplot(...) returns a handle to the function line object created by fplot.

fplot(AX,...) plots into the axes AX instead of the current axes.

Examples:
fplot(@sin)
fplot(@(x) x.^2.*sin(1./x),[-1,1])
fplot(@(x) sin(1./x), [0 0.1])

If your function cannot be evaluated for multiple x values at once,
you will get a warning and somewhat reduced speed:
f = @(x,n) abs(exp(-1j*x*(0:n-1))*ones(n,1));
fplot(@(x) f(x,10),[0 2*pi])

See also fplot3, fsurf, fcontour, fimplicit, plot, function_handle.

Reference page for fplot
fplot(@sin,[0 2*pi])
but you might argue that we could do the same thing without a function handle, a good old-fashioned way with plot.
plot(0:0.01:2*pi, sin(0:0.01:2*pi))
Sure, but here we had to provide the actual vector of x values twice while fplot does all that for us, and it gets better, look at this example.
fplot(@tan,[0,pi])
now, lets plot this via plot function
plot(0:0.01:pi, tan(0:0.01:pi))
not so good, now let change the resolution
plot(0:0.001:pi, tan(0:0.001:pi))
still not good.
now we can understand why fplot is important.

Anonymous function

Let's say we have a polynomial expression that we need to use a few times in our program. We could create a sub function, but it would be overkill to do that for a single expression, not to mention that we'd need to make up a meaningful name for the function. Instead, MATLAB allows us to create a so-called anonymous function as a single expression and return a function handle to it all in one fell swoop.
poly=@(x) 2*x.^3-x.^2+2*x-12;
poly(1)
ans = -9
poly(0:5)
ans = 1×6
-12 -9 4 39 108 223
plot(-10:10,poly(-10:10))
fplot(poly,[-10,10])
xnf=@(x,y) x+y;
xnf(1,2)
ans = 3
x=1000
x = 1000
y=2000
y = 2000
xnf(11,12)
ans = 23
x,y
x = 1000
y = 2000
Here we first gave x and y the values 1,000 and 2,000. Then we called xfn, giving its local variables with the same names x and y, the values 10 and 12. After the function return, we checked x and y and found that they still have the same values that they had before the function was called. So the variables outside the function are not accessible inside the function if they have the same names as one or the arguments.
c=10;
f=@(x) c*x;
f(3)
ans = 30
If it were a global reference to c, then if we change c to 11 and rerun the function, we'd get 33, which is exactly what would happen if f were the handle of an ordinary function that made a global reference to c. But that is not what happens for an anonymous function.
Here we change c from 10 to 11, but the function did not change. It's still multiplied its input argument by 10.
c=11;
f(3)
ans = 30
You can even remove c from the workplace and it'll still have no effect on our function.
clear c
f(3)
ans = 30
Aanonymous function construct is called anonymous, which means literally not having a name. Didn't we give the name f to the anonymous function that we just defined, for example? Well, no. We put the handle for this function into a variable named f, but the function itself had no name. Contrast that with the first example we gave of a function handle.
trig=@sin
trig = function_handle with value:
@sin
In that case, the name of the function is sine and trig is the name of the variable that holds the handle for sine. We can drive the anonymity of an anonymous function home by using f plot again.Here we've given f plot an anonymous function whose expression is x plus the sine of x.
fplot(@(x) x+sin(x),[-5,5])
It plots the function from minus five to five, and yet there's no name for the function anywhere. So we've seen how to define anonymous functions and we've seen examples with one input argument and two input arguments. Of course you can have as many input arguments as you wish. Multiple output arguments are also supported, but in a very limited way. The only way to get multiple outputsis to have the expression, that is the body of the anonymous function, be a call of a function that already returns multiple arguments. Here's an example.
smax=@(A) max(A.^2)
smax = function_handle with value:
@(A)max(A.^2)
[mx ind]=smax([1 2;3 4])
mx = 1×2
9 16
ind = 1×2
2 2
with anonymous functions, you can get multiple outputs only by calling a function that already produces multiple outputs. But you can get a lot of versatility by using the deal function
xyz=@(x,y) deal(x*y, x+y)
xyz = function_handle with value:
@(x,y)deal(x*y,x+y)
[p, s]=xyz(10,20)
p = 200
s = 30
A normal function is a function name and can have any number of statements in its body, but an anonymous function has no name, and it can have only one statement in its body. Also, if you want to have multiple outputs from an anonymous function, it's one executable statement has to be a call to a function that already returns multiple outputs.
In addition to the three kinds of functions that we've seen so far, the main function, the sub-function, and the anonymous function, there's one more function that we need to talk about, it's called the nested function.

Nested Function

it's similar to a sub-function in that it lives in an M-file with a main function, just like a sub-function does. However, a nested function is actually defined inside the body of another function, also called its parent function.
% function [y1, y2] = first_nested_example(x)
% c = 10;
% sub(c,x);
% y1 = inner(x);
% %nested function start here
% function out = inner(in)
% out = c*in;
% end
% %nested function end here
% c = 11;
% sub(c,x)
% y2 = inner(x);
% end
% %sub function start here
% function sub(in1,in2)
% fprintf('Multiplying %d times %d\n',in1,in2)
% end
% %sub function end here
A nested function has access not only to all the variables inside it, but also to variables inside its parent function. Similarly, the parent function has access not only to all the variables inside it, but also to variables inside it's nested functions.
[a1,b1]=first_nested_example(3)
Multiplying 10 times 3
Multiplying 11 times 3
a1 = 30
b1 = 33
take an another example
% function circle_area = assignment_rule(r)
%
% calculate_area
% fprintf('Area of circle with radius %.1f = %.1f\n',r,circle_area)
%
% function calculate_area
% circle_area = pi*r^2;
% end
% end
assignment_rule(3)
Area of circle with radius 3.0 = 28.3
ans = 28.2743
% function A
% xA = 1;
% function B
% xB = 2;
% function C
% xC = 3;
% show('C','xA',xA)
% show('C','xB',xB)
% show('C','xC',xC)
% end % C
% show('B','xA',xA)
% show('B','xB',xB);
% C
% D
% end % B
% function D
% xD = 4;
% show('D','xA',xA);
% show('D','xD',xD);
% end % D
% show('A','xA',xA)
% B
% D
% end % A
% function show(funct,name,value)
% fprintf('in %s: %s = %d\n',funct,name,value);
% end
you can see here the accessibilities of all the variables. In A, xA is accessible; in B, xA and xB are accessible; in C, xA, xB and xC are accessible, and in D, xA and xD are accessible, and D is called twice, once down here in A, and once up here in B. This second call of D brings up a visibility rule for nested functions that we haven't mentioned yet, it's the rule that tells us where a function is accessible, where it can be called. There are actually three paths for accessibility. A parent can call a child as for example here, A calls B and D, but it can't call a grandchild, so A can't call C. A sibling can call a sibling, has for example, B can call D, and a descendant can call any ancestor, so C can call B or A, for example. The sibling calling feature is interesting because of the difference from the variable sharing rule. While sibling functions can call each other, they can't access each other's local variables. Access to functions goes up and down and side to side, but access to variable goes only up and down.
A
in A: xA = 1
in B: xA = 1
in B: xB = 2
in C: xA = 1
in C: xB = 2
in C: xC = 3
in D: xA = 1
in D: xD = 4
in D: xA = 1
in D: xD = 4
Remember this, we set c equal to 10,
c=10;
f=@(x) c*x;
f(3)
ans = 30
c=11;
f(3)
ans = 30
clear c
f(3)
ans = 30
The value 10 is baked into the anonymous function, to change it, you'd have to define the anonymous function again. Let's suppose you need to do that, and you need to do it multiple times with different values of c, but suppose also that like me, you don't want to spend your valuable time defining an anonymous function over and over. Well, you can write a function to do it for you like this.
% function fh = get_anon_handle(c)
%
% fh = @(x) c*x;
%
% end
f10=get_anon_handle(10)
f10 = function_handle with value:
@(x)c*x
f11=get_anon_handle(11)
f11 = function_handle with value:
@(x)c*x
f10(3)
ans = 30
f11(3)
ans = 33
so, here via a function we can define anonymas with different c
% function fh = get_polynomial_handle(p)
%
% function polynomial = poly(x)
% polynomial = 0;
% for ii = 1:length(p)
% polynomial = polynomial + p(ii).*x.^(ii-1);
% end
% end
%
% fh = @poly;
% end
pc=get_polynomial_handle([-4,-1,3,1])
pc = function_handle with value:
@get_polynomial_handle/poly
pq=get_polynomial_handle([-10,0,7])
pq = function_handle with value:
@get_polynomial_handle/poly
pc(1)
ans = -1
pq(1)
ans = -3
It's just like what we saw for the anonymous function. Once you create a handle to a function, the values of it's non-local variables in this case p are baked in. So that's it for nested functions. But before we leave, let's plot pc and pq using f plot, we plot them over the range from minus 3 to 2.
fplot(pc,[-3,2]);
hold on
fplot(pq,[-3,2])
let's finish by recapping what we've learned.

Assignment

Problem 1: Autograder

Write a function that compare two different functions' results.
help isequal
isequal True if arrays are numerically equal.
isequal(A,B) returns logical 1 (TRUE) if arrays A and B are the same
size and contain the same values, and logical 0 (FALSE) otherwise.

If A is defined and you set B = A, isequal(A,B) is not necessarily
true. If A or B contains a NaN element, isequal returns false because
NaNs are not equal to each other by definition.

isequal(A,B,C,...) returns logical 1 if all the input arguments are
numerically equal, and logical 0 otherwise.

When comparing numeric values, isequal does not consider the class
of the values in determining whether they are equal. In other words,
INT8(5) and SINGLE(5) are considered equal. This is also true when
comparing numeric values with certain nonnumeric values. Numeric 1
is equal to logical 1. The number 65 is equal to the character 'A'.

When comparing handle objects, use EQ or the == operator to test
whether objects are the same handle. Use isequal to test if objects
have equal property values, even if those objects are different
handles.

isequal recursively compares the contents of cell arrays and
structures. If all the elements of a cell array or structure are
numerically equal, isequal returns 1.

When comparing structures, the order in which the fields of the
structures were created is not important. As long as the structures
contain the same fields, with corresponding fields set to equal values,
isequal considers the structures to be equal.

See also isequaln, eq.

Reference page for isequal
Other functions named isequal
% function f=grader(fn1,fn2, varargin)
%
% for n=1:length(varargin);
% if isequal(fn1(varargin{n}),fn2(varargin{n}));
% f=true;
% else
% f=false;
% end
% end
%
% end
grader(@sin,@max,0)
ans = logical
1
grader(@sin,@max,0,1)
ans = logical
0
grader(@cos,@cos,0,1,[-pi,0,pi])
ans = logical
1
oficial solution
*********
% function pass = cgrader(fn1,fn2,varargin)
% pass = false;
% for ii = 1:length(varargin)
% if ~isequal(fn1(varargin{ii}),fn2(varargin{ii}))
% return;
% end
% end
% pass = true;
% end
*******

Problem 2: Fun with polynomial

Mixed Mode Arithmetic

single- Single precision floating pont number.(32 bit)
double-Double precision floating pont number (64 bit)
4*pi
ans = 12.5664
int8(200)+int8(300)
ans = int8
127
four times pi here has one operator multiplication, also known as times and two operations four and pi. Because they're too operands, we call this a binary operation. The type of each of these operations is double, which is the default and MATLAB. But you can specify different types by using MATLABs casting functions like at eight for example.
That's because 500 is too large to fit into a little old and eight. And so the result we get is the closest number to 500 that lies inside the range of numbers that do fit into an innate, which goes from minus 128 to plus 127.
So far, all our operations have used operations of the same type. So none of these expressions is an example of mixed mode arithmetic. We'll get there, but in the meantime, there's another way not to have operations with mixed types, and that's just a have one operand like this.
-3
ans = -3
We still have one operator, the minus, but only one operand the three This is called a unitary operation.
here is a table showing the shape compatibility rules for binary operators.
Here we have five rules for a binary operation, which we show here as an operand x and operator op and a second operand y. Where x and y could be any scaler's or two dimensional arrays who shapes are compatible for the operator op. For example, plus minus, and all the dot operators which are known collectively, is array operators require that the two operations x and y have the same size and shape.
For example, plus minus, and all the dot operators which are known collectively, is array operators require that the two operations x and y have the same size and shape.
Rule B is for multiplication, also known as matrix multiplication. And it says that the size of the second dimension of x must equal the size of the first dimension of y.
Or to put it another way, the number of columns of x must equal the number of rows of y. Here's an example that follows that rule.Yeah, it follows it, because the first operandi has three columns in the second operandi has three rows.
[1 2 3;3 4 5]*[6;7;8]
ans = 2×1
44
86
if weswop will get error.
The last rule E for the exponentiation operator, also known as the power operator, says that both operations must be square. So for example, 2 buy 2 is fine, but 2 by 3 is not, and one or both of them must be scaler.
Let's try it for a three by three matrix raised to a scaler power.
[1 2 3;2 5 8;9 6 3]^2
ans = 3×3
32 30 28
84 77 70
48 66 84
but if do non square matrix to a power-
it will give error.
So the last rule required that one of the operations be a scaler. And on the subject of scaler, I need to point out that the other four rules include special cases for scaler is that we haven't mentioned yet. We had those special cases.
The rules look like this.
The special cases are that if one operand is a scaler, the other operand could be any shape it all. The operator is applied to the scaler and each element in the array, with the only stipulation being that for the two slash operators, rule C and D scaler must be in the denominator These five rules have been part of my lab for decades but in September of 2016, when version 2016b appeared.
It's rule F here, which says that you can now add vectors to arrays or subtract vectors from arrays. Or perform any array operation for that matter not just any vector in any array though. You can only do it if the vector is either a row vector with a length equal to the row length of the array. Or a column vector with the length equal to the column length of the array.

Script examples of binary arithmetic operations

A = [100 200 300; 400 500 600]
A = 2×3
100 200 300
400 500 600
c = [7;9]
c = 2×1
7
9
A_plus_c = A + c
A_plus_c = 2×3
107 207 307
409 509 609
it added the column vector to each column of the array.7 was added to every element on the first row, and 9 was added to every element on the second row.
if you're driving an old installed model older than 2016b, you'll get an error message that says matrix dimensions must agree. But don't despair, you can accomplish the same thing by using the built in function, repmat, to make an array of copies of the vector.
C = repmat(c,1,3)
C = 2×3
7 7 7
9 9 9
now we can add
A+C
ans = 2×3
107 207 307
409 509 609
Here according rule 6-
rule-2 and 5
int8(123) - int8(40)
ans = int8
83
uint16([1 2; 3 4]) + uint16([64 28;10 55])
ans = 2×2 uint16 matrix
65 30
13 59
%uint16([1 2; 3 4])* uint16([64 28;10 55])
uint16([1 2; 3 4])*uint16(64)
ans = 2×2 uint16 matrix
64 128
192 256
uint16(4)*uint16([64 28; 10 55])
ans = 2×2 uint16 matrix
256 112
40 220
uint16([1 2; 3 4])*64
ans = 2×2 uint16 matrix
64 128
192 256
4*uint16([64 28; 10 55])
ans = 2×2 uint16 matrix
256 112
40 220
single(1) + double(2)
ans = single
3
int64(3)^2
ans = int64
9
%int64(9)^0.5
%sqrt(int64(9))
as matlab has to give whole no in output (as above example int64 9) but fractional power dont give whole no so cause error.
In fact, there is just one rule. The type of the output of any legal arithmetic operation is the same as the type of the operation that occupies the least space and memory.
So, for example, if we had an 8 bit integer to a double, the result is an 8 bit integer. Because an 8 bit integer occupies less space than a double. Which you may remember uses 64 bits.
Or say we multiply an array of singles by an array of doubles. And the type of the output is single because a single occupies only 32 bits.
Extending the rule to non mixed mode arithmetic. When both operands have the same type. Then, of course, the output has that same type too.
n = int16(9876)
n = int16
9876
x = 12
x = 12
So here we've added a double to a 16 bit integer. Since the 16 bit integer occupies only 16 bits, while the double occupies 64 bits, the result is an int6. Here's more operations. These are all mixed mode arithmetic operations because the operations have different types. And in every case we get an int 16.
x + n
ans = int16
9888
n*x
ans = int16
32767
n/x
ans = int16
823
n^x
ans = int16
32767
x/n
ans = int16
0
as int cant holde fraction.
x/9876
ans = 0.0012
here it eill give ans in fraction.
So why does MATLAB choose the smaller type for its result? Well, that's a very good question. As a matter of fact, most other computer programming languages do give you a double when you mix a double in an integer. But MATLAB has a very good answer to this very good question. It produces an integer to save memory.
Let's see an example of how MATLAB approach saves memory. I have an image of the MATLAB logo saved as a PNG file here in this folder.
Let's read that into a variable and display it.
clear;
M=imread('matlab.png');
imshow(M)
As you can see over here in the workspace, the variable M,
which contains the image, is a 400 by 400 by 3 array, meaning that it has 400 columns, 400 rows and 3 pages. Each page of the array contains a 400 by 400 array of color intensities. One page each for the red, green and blue colors, also known as an RGB image, in which each set of red, green and blue values makes up one pixel.
What's most important to us though here is that the array is of type Uint8.
We can calculate how much memory space this image requires, but let's take the easy way and let the function whos tell us, 480,000 bytes.
whos
Name Size Bytes Class Attributes

D 400x400x3 480000 uint8
M 400x400x3 480000 uint8
Now, let's do a little image processing on it. I'll create a darker version of the image by dividing all the intensity values by three.
D=M/3;
imshow(D)
whos
Name Size Bytes Class Attributes

D 400x400x3 480000 uint8
M 400x400x3 480000 uint8
So the size of the image has not changed.
480,000 bytes for each of them.
That's because of MATLAB rule that says that the type of the output of the arithmetic operation that produced D is the same is the type of its smallest operand.
The two operands were M, which is a Uint8 and three, which is a double, so the result is a Uint8. If we were using a language like say, C or C++ or Java, which would produce a double instead of Uint8 as output, the result would be eight times as big. Here's the equivalent operation in those languages.
D=double(M)/3;
What we've done is converted the eight bit M into a 64 bit double.
So now the type of the operand that was taking less space has been changed to match the type of the operand, and that takes more space. This step, which is done before the arithmetic operation is applied, is called widening and widening is exactly what is done by C, C++ and Java from mixed mode arithmetic operations. So let's see how big D is now.
whos
Name Size Bytes Class Attributes

D 400x400x3 3840000 double
M 400x400x3 480000 uint8
Almost four megabytes. You may think that four megabytes is nothing these days, and you would be right, but once you start dealing with medical images such as MRI or CT, which can consist of over 100 individual images. Or if you think of videos that can have 30 or even 60 frames per second. All of a sudden we're talking about gigabytes and a factor of it becomes crucial. MATLABs approach, by comparison, is to use narrowing like this.
D=M/uint8(3);
So now the type of the operation which takes more space is changed to match the type of one that takes less space, thereby saving memory. And it's not just a matter of saving memory, operations on wider operand take more time too. So MATLABs approach of narrowing in mixed mode arithmetic saves both space and time. The downside is that during narrowing values around it off and you'll find people online railing away about that, but in fact the difference of 0.5 is rarely even detectable in an image.
And you can always override this behavior by explicitly widening the smaller operand.
If you do wide and make sure you widen the operand and as we have done and not the result of the operation, if you widen the result of the operation, you could lose accuracy.
Here's a simpler example to show what happens.
a=int8(17)
a = int8
17
b=double(a)/2
b = 8.5000
c=double(a/2)
c = 9
So, B and C have the same type double, but they have different values. Do you see why?
Well, it's because for B, we widen the operand and for c, we widened the result of the operation. When we calculate B here, we first convert A to a double and then divide by 2.
And since 2 is by default, also a double, the results of the operation is a double, but when we calculate C, we first divide by 2.
And since a is an int8, the result is an int8, which means that the exact answer 8.5 is rounded to the end of your 9. We then convert that 9 from an int8 to a double.
And now let's see what happens if we use an int8 type for the 2, as well as for the A.
f=int8(2)
f = int8
2
b=double(a)/f
b = int8
9
c=double(a/f)
c = 9
This time B and C have different types, but the same value.
Well, here again for B, we widen the operand and for C, we widen the result of the operation. But this time since F is an int8, the result for B is an int8, so the result is rounded to 9.
Summary

Assignment